package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"nas_file/db" // 修改为正确的包路径

	"github.com/gorilla/sessions"
)

var (
	store    = sessions.NewCookieStore([]byte("your-secret-key-make-it-very-long-and-random"))
	database *db.Database // 添加全局数据库变量
)

// 认证中间件
func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		session, _ := store.Get(r, "session-name")
		if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
			http.Redirect(w, r, "/login", http.StatusSeeOther)
			return
		}
		next.ServeHTTP(w, r)
	})
}

// 登录处理
func handleLogin(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var creds struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}

	if err := json.NewDecoder(r.Body).Decode(&creds); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	valid, err := database.ValidateUser(creds.Username, creds.Password)
	if err != nil {
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	if !valid {
		http.Error(w, "Invalid credentials", http.StatusUnauthorized)
		return
	}

	session, _ := store.Get(r, "session-name")
	session.Values["authenticated"] = true
	session.Values["username"] = creds.Username
	session.Save(r, w)

	w.WriteHeader(http.StatusOK)
}

// 登出处理
func handleLogout(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session-name")
	session.Values["authenticated"] = false
	session.Save(r, w)
	http.Redirect(w, r, "/login", http.StatusSeeOther)
}

// 解析文件名中的时间信息
func parseFileName(fileName string) (cameraType string, startTime, endTime time.Time, err error) {
	// 分割文件名
	parts := strings.Split(fileName, "_")
	if len(parts) != 3 {
		return "", time.Time{}, time.Time{}, fmt.Errorf("invalid filename format")
	}

	// 判断摄像头类型
	switch parts[0] {
	case "00":
		cameraType = "旋转摄像头"
	case "10":
		cameraType = "固定摄像头"
	default:
		return "", time.Time{}, time.Time{}, fmt.Errorf("unknown camera type")
	}

	// 解析开始时间
	startTime, err = time.ParseInLocation("20060102150405", parts[1], time.Local)
	if err != nil {
		return "", time.Time{}, time.Time{}, fmt.Errorf("failed to parse start time: %v", err)
	}

	// 解析结束时间
	endTime, err = time.ParseInLocation("20060102150405", strings.TrimSuffix(parts[2], ".mp4"), time.Local)
	if err != nil {
		return "", time.Time{}, time.Time{}, fmt.Errorf("failed to parse end time: %v", err)
	}

	return cameraType, startTime, endTime, nil
}

// 修改 processFile 函数，添加数据库支持和文件复制
func processFile(sourcePath, outputPath, fileName string, database *db.Database) error {
	fmt.Printf("正在处理文件: %s\n", fileName)

	sourceFilePath := filepath.Join(sourcePath, fileName)

	// 检查文件是否已处理
	processed, err := database.IsFileProcessed(sourceFilePath)
	if err != nil {
		return fmt.Errorf("检查文件处理状态失败: %v", err)
	}
	if processed {
		fmt.Printf("文件已处理过，跳过: %s\n", fileName)
		return nil
	}

	cameraType, startTime, endTime, err := parseFileName(fileName)
	if err != nil {
		return fmt.Errorf("error parsing filename %s: %v", fileName, err)
	}

	newDirPath := filepath.Join(
		outputPath,
		cameraType,
		fmt.Sprintf("%d年", startTime.Year()),
		fmt.Sprintf("%02d月", startTime.Month()),
		fmt.Sprintf("%02d日", startTime.Day()),
		fmt.Sprintf("%02d时", startTime.Hour()),
	)

	err = os.MkdirAll(newDirPath, 0755)
	if err != nil {
		return fmt.Errorf("error creating directories: %v", err)
	}

	newFileName := fmt.Sprintf("%02d点%02d分%02d秒-%02d点%02d分%02d秒.mp4",
		startTime.Hour(), startTime.Minute(), startTime.Second(),
		endTime.Hour(), endTime.Minute(), endTime.Second())

	targetFilePath := filepath.Join(newDirPath, newFileName)

	// 复制文件而不是移动
	err = copyFile(sourceFilePath, targetFilePath)
	if err != nil {
		return fmt.Errorf("复制文件失败: %v", err)
	}

	// 修改数据库记录调用，传入时间参数
	err = database.RecordProcessedFile(sourceFilePath, targetFilePath, startTime, endTime)
	if err != nil {
		// 如果数据库记录失败，删除已复制的文件
		os.Remove(targetFilePath)
		return fmt.Errorf("记录文件处理状态失败: %v", err)
	}

	fmt.Printf("✓ 成功处理文件: %s\n", fileName)
	fmt.Printf("  └─ 已复制到: %s\n", targetFilePath)
	return nil
}

// 新增文件复制函数
func copyFile(src, dst string) error {
	sourceFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sourceFile.Close()

	destFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, sourceFile)
	return err
}

func main() {
	fmt.Println("=== 视频文件整理程序 ===")

	// 修改参数检查
	if len(os.Args) < 2 || len(os.Args) > 3 {
		fmt.Println("使用方法: go run main.go <视频文件目录路径> [输出目录路径]")
		fmt.Println("  - 视频文件目录路径: 必填，源视频文件所在目录")
		fmt.Println("  - 输出目录路径: 可选，处理后的文件存放目录，默认与源目录相同")
		os.Exit(1)
	}

	sourceDirPath := os.Args[1]
	outputDirPath := sourceDirPath // 默认输出目录与源目录相同

	// 如果提供了输出目录参数
	if len(os.Args) == 3 {
		outputDirPath = os.Args[2]
		// 确保输出目录存在
		if err := os.MkdirAll(outputDirPath, 0755); err != nil {
			fmt.Printf("❌ 创建输出目录失败: %v\n", err)
			os.Exit(1)
		}
	}

	fmt.Printf("\n源目录: %s\n", sourceDirPath)
	fmt.Printf("输出目录: %s\n\n", outputDirPath)

	dbPath := filepath.Join("db", "processed_files.db")
	database, err := db.NewDatabase(dbPath)
	if err != nil {
		fmt.Printf("❌ 初始化数据库失败: %v\n", err)
		os.Exit(1)
	}
	defer database.Close()

	fmt.Println("✓ 数据库初始化成功")

	// 创建一个通道用于接收文件处理完成的信号
	done := make(chan bool)

	// 在后台处理文件
	go func() {
		processFiles(sourceDirPath, outputDirPath, database)
		done <- true
	}()

	// 在新的 goroutine 中等待文件处理完成
	go func() {
		<-done
		fmt.Println("\n✓ 所有文件处理完成，Web服务继续运行中...")
		fmt.Println("\n=== 启动服务 ===")
		fmt.Println("1. Web界面访问地址:")
		fmt.Println("   http://localhost:8080")
		fmt.Println("2. 文件处理进行中，请勿关闭程序...")
		fmt.Println("3. 使用 Ctrl+C 可以停止服务")
		fmt.Println("===================================")
	}()

	// 在主线程中运行HTTP服务
	startHTTPServer(database)
}

// 新增函数：处理文件
func processFiles(sourceDirPath, outputDirPath string, database *db.Database) {
	fmt.Println("\n开始处理文件...")

	entries, err := os.ReadDir(sourceDirPath)
	if err != nil {
		fmt.Printf("❌ 读取目录失败: %v\n", err)
		return
	}

	var totalFiles, successCount int
	var failedFiles []string

	// 统计需要处理的文件数量
	for _, entry := range entries {
		if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".mp4") {
			totalFiles++
		}
	}

	fmt.Printf("找到 %d 个视频文件需要处理\n", totalFiles)

	// 处理文件
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		fileName := entry.Name()
		if !strings.HasSuffix(fileName, ".mp4") {
			continue
		}

		err := processFile(sourceDirPath, outputDirPath, fileName, database)
		if err != nil {
			fmt.Printf("❌ 处理失败: %s\n  └─ 错误信息: %v\n", fileName, err)
			failedFiles = append(failedFiles, fileName)
		} else {
			successCount++
			fmt.Printf("进度: %d/%d\n", successCount, totalFiles)
		}
	}

	// 打印处理结果统计
	fmt.Printf("\n=== 文件处理结果 ===\n")
	fmt.Printf("总文件数: %d\n", totalFiles)
	fmt.Printf("成功处理: %d\n", successCount)
	fmt.Printf("处理失败: %d\n", len(failedFiles))

	if len(failedFiles) > 0 {
		fmt.Println("\n以下文件处理失败:")
		for _, file := range failedFiles {
			fmt.Printf("- %s\n", file)
		}
	}
}

func startHTTPServer(db *db.Database) {
	database = db // 设置全局数据库变量

	// 登录相关路由
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodGet {
			http.ServeFile(w, r, "templates/login.html")
			return
		}
	})
	http.HandleFunc("/api/login", handleLogin)
	http.HandleFunc("/logout", handleLogout)

	// 受保护的路由
	http.Handle("/", authMiddleware(http.HandlerFunc(handleIndex)))
	http.Handle("/api/videos", authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		handleVideos(w, r, database)
	})))

	// 静态文件访问
	fileServer := http.StripPrefix("/video/", http.FileServer(http.Dir("video")))
	http.Handle("/video/", authMiddleware(fileServer))

	// 获取本机所有IP地址
	addrs, err := net.InterfaceAddrs()
	if err == nil {
		fmt.Println("\n可通过以下地址访问:")
		for _, addr := range addrs {
			// 检查IP地址类型
			if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
				if ipnet.IP.To4() != nil {
					fmt.Printf("http://%s:8080\n", ipnet.IP.String())
				}
			}
		}
	}
	fmt.Println("http://localhost:8080")
	fmt.Println("\n等待访问中...")

	// 添加获取当前用户信息的路由
	http.Handle("/api/current-user", authMiddleware(http.HandlerFunc(handleCurrentUser)))

	// 添加修改密码的处理函数
	http.Handle("/api/change-password", authMiddleware(http.HandlerFunc(handleChangePassword)))

	// 尝试启动服务器
	if err := http.ListenAndServe(":8080", nil); err != nil {
		fmt.Printf("\n❌ Web服务器启动失败: %v\n", err)
		os.Exit(1)
	}
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "templates/index.html")
}

// 添加分页参数结构
type PageParams struct {
	Page     int `json:"page"`
	PageSize int `json:"pageSize"`
	Total    int `json:"total"`
}

func handleVideos(w http.ResponseWriter, r *http.Request, database *db.Database) {
	startStr := r.URL.Query().Get("start")
	endStr := r.URL.Query().Get("end")
	cameraType := r.URL.Query().Get("cameraType")

	// 获取分页参数
	page, _ := strconv.Atoi(r.URL.Query().Get("page"))
	pageSize, _ := strconv.Atoi(r.URL.Query().Get("pageSize"))

	if page < 1 {
		page = 1
	}
	if pageSize < 1 {
		pageSize = 20 // 默认每页20条
	}

	start, err := time.Parse("2006-01-02T15:04", startStr)
	if err != nil {
		http.Error(w, "无效的开始时间", http.StatusBadRequest)
		return
	}

	end, err := time.Parse("2006-01-02T15:04", endStr)
	if err != nil {
		http.Error(w, "无效的结束时间", http.StatusBadRequest)
		return
	}

	// 先获取总数
	total, err := database.CountVideosByTimeRange(start, end, cameraType)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 查询分页数据
	records, err := database.QueryVideosByTimeRangeWithPaging(start, end, cameraType, page, pageSize)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 返回结果
	result := struct {
		Records []db.FileRecord `json:"records"`
		Page    PageParams      `json:"page"`
	}{
		Records: records,
		Page: PageParams{
			Page:     page,
			PageSize: pageSize,
			Total:    total,
		},
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(result)
}

// 添加获取当前用户信息的处理函数
func handleCurrentUser(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session-name")
	username, ok := session.Values["username"].(string)
	if !ok {
		http.Error(w, "未登录", http.StatusUnauthorized)
		return
	}

	response := struct {
		Username string `json:"username"`
	}{
		Username: username,
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// 添加修改密码的处理函数
func handleChangePassword(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var req struct {
		OldPassword string `json:"oldPassword"`
		NewPassword string `json:"newPassword"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	session, _ := store.Get(r, "session-name")
	username, ok := session.Values["username"].(string)
	if !ok {
		http.Error(w, "未登录", http.StatusUnauthorized)
		return
	}

	err := database.ChangePassword(username, req.OldPassword, req.NewPassword)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
}
